/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.jj.parallax;

import java.util.Vector;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class Parallax extends Activity {
    private SensorManager mSensorManager;
    private MySensor mSensor;
    private Vector<Level> levels;
    private Boolean toggledImage;
    final int sensitivity = 20;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        toggledImage = false;
        levels = new Vector<Level>();

        mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        mSensor = new MySensor();

        setContentView(R.layout.activity_picture);
        setAlternateImage();
    }

    private void setDefaultImage() {
        toggledImage = false;
        Level level = new Level(this, R.drawable.bg, 0, 0, 0);
        level.makeBackground();

        level = new Level (this, R.drawable.level1, 200, 1200, 3);
        levels.addElement(level);

        level = new Level (this, R.drawable.level2, 400, 300, 3);
        levels.addElement(level);

        level = new Level (this, R.drawable.level3, 200, 1000, 4);
        levels.addElement(level);

        level = new Level (this, R.drawable.level4, 500, 800, 6);
        levels.addElement(level);

        level = new Level (this, R.drawable.level5, 500, 800, 8);
        levels.addElement(level);
    }

    private void setAlternateImage() {
        toggledImage = true;
        Level level = null;

        for (int i = 1; i < 20; i++) {
            level = new Level(this, R.drawable.ring, 0, 0, i);
            levels.addElement(level);
            level.scaleByLevelAndCenter();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_picture, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.toggle:
                toggleImage();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void toggleImage() {
        ViewGroup group = (ViewGroup) findViewById(R.id.main_group);
        group.removeAllViews();

        if (toggledImage) {
            setDefaultImage();
        } else {
            setAlternateImage();
        }
    }

    @Override
    protected void onResume() {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onResume();
        mSensor.start();
    }

    @Override
    protected void onPause() {
        // Ideally a game should implement onResume() and onPause()
        // to take appropriate action when the activity looses focus
        super.onPause();
        mSensor.stop();
    }


    class MySensor implements SensorEventListener {
        private Sensor mRotationVectorSensor;
        private final float[] mRotationMatrix = new float[16];

        public MySensor() {
            // find the rotation-vector sensor
            mRotationVectorSensor = mSensorManager.getDefaultSensor(
                    Sensor.TYPE_ROTATION_VECTOR);
            mRotationMatrix[ 0] = 1;
            mRotationMatrix[ 4] = 1;
            mRotationMatrix[ 8] = 1;
            mRotationMatrix[12] = 1;
        }

        public void start() {
            // enable our sensor when the activity is resumed, ask for
            // 10 ms updates.
            mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
        }

        public void stop() {
            // make sure to turn our sensor off when the activity is paused
            mSensorManager.unregisterListener(this);
        }

        public void onSensorChanged(SensorEvent event) {
            // we received a sensor event. it is a good practice to check
            // that we received the proper event
            if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {

                SensorManager.getRotationMatrixFromVector(mRotationMatrix , event.values);
                float[] orientation = new float[3];
                SensorManager.getOrientation(mRotationMatrix, orientation);

                for(Level level: levels) {
                    int pitch = (int) (orientation[1] * level.getDepth() * sensitivity);
                    int yaw = (int) (orientation[2] * level.getDepth() * sensitivity);
                    level.move(yaw, pitch);
                }
            }
        }

        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    }

    class Level implements View.OnTouchListener {
        private int baseTop;
        private int baseLeft;
        private int depth;
        private ImageView image;
        private Boolean disableParallax;
        private int xMove;
        private int yMove;


        Level(Context ctx, int imgId, int top, int left, int depth){
            baseTop = top;
            baseLeft = left;
            this.depth = depth;
            disableParallax = false;
            xMove = 0;
            yMove = 0;

            image = new ImageView(ctx);
            Bitmap bgBitmap = BitmapFactory.decodeResource(getResources(), imgId);
            image.setImageBitmap(bgBitmap);

            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                    RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            params.leftMargin = left;
            params.topMargin = top;
            image.setLayoutParams(params);

            ViewGroup group = (ViewGroup) findViewById(R.id.main_group);
            group.addView(image);
            image.setOnTouchListener(this);
        }

        public void move(int top, int left) {
            if (disableParallax)
                return;
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) image.getLayoutParams();
            params.leftMargin = baseLeft - left;
            params.topMargin = baseTop - top;
            image.setLayoutParams(params);
        }

        public void makeBackground() {
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) image.getLayoutParams();
            params.height = RelativeLayout.LayoutParams.MATCH_PARENT;
            params.width = RelativeLayout.LayoutParams.MATCH_PARENT;
            image.setLayoutParams(params);
            image.setOnTouchListener(null);
        }

        public void scaleByLevelAndCenter() {
            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            int width = size.y;
            int height = size.x;
            final int scale = 30;

            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) image.getLayoutParams();
            params.height = scale * getDepth();
            params.width = scale * getDepth();
            params.topMargin = (width / 2) - (params.width / 2) - 100;
            params.leftMargin = (height / 2) - (params.height / 2) - 100;

            baseLeft = params.leftMargin;
            baseTop = params.topMargin;
            image.setLayoutParams(params);
        }

        public int getDepth() {
            return depth;
        }

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            final int X = (int) event.getRawX();
            final int Y = (int) event.getRawY();
            disableParallax = true;
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) image.getLayoutParams();
                    xMove = X - lParams.leftMargin;
                    yMove = Y - lParams.topMargin;
                    break;
                case MotionEvent.ACTION_UP:
                    disableParallax = false;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                    break;
                case MotionEvent.ACTION_MOVE:
                    baseLeft = X - xMove;
                    baseTop = Y - yMove;
                    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) image.getLayoutParams();
                    layoutParams.leftMargin = baseLeft;
                    layoutParams.topMargin = baseTop;
                    image.setLayoutParams(layoutParams);
                    break;
            }
            return true;
        }
    }
}